package admin

import (
	j_redis "config-client-v1/init/j-redis"
	"config-client-v1/model"
	"config-client-v1/utils/tools"
	"context"
	"encoding/json"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"strconv"
	"time"
)

type LoginController struct {
}

func (con LoginController) Captcha(ctx *gin.Context) {
	id, b64s, err := model.GenerateCaptcha()
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": err,
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"id":   id,
			"b64s": b64s,
		},
	})
}

func (con LoginController) DoLogin(ctx *gin.Context) {
	param := struct {
		VCode     string `json:"vcode"`
		CaptchaId string `json:"captchaId"`
		ProjectID int    `json:"project_id" binding:"required"`
		Username  string `json:"username" binding:"required,max=30"`
		Password  string `json:"password" binding:"required,max=30"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	//code := param.VCode
	//captchaId := param.CaptchaId
	username := param.Username
	password := param.Password
	password = tools.Md5(password + LOGIN_KEY)
	//verifyBoolean := model.VerifyCaptcha(captchaId, code)
	//if !verifyBoolean {
	//	ctx.JSON(200, gin.H{
	//		"code":    1,
	//		"message": "验证码错误",
	//		"data":    param,
	//	})
	//	return
	//}
	user := model.User{}
	err = model.DB.Where("project_id = ? AND username = ? AND password = ?", param.ProjectID, username, password).Find(&user).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": err.Error(),
		})
		return
	}

	if user.Id == 0 {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "账号密码不匹配",
		})
		return
	}
	if user.Status == 2 {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "账号被冻结",
		})
		return
	}
	now := tools.GetNow()
	// 登录成功, token 存入数据库和redis
	ip := ctx.ClientIP()
	token := tools.Md5(username + tools.GetNow() + tools.GetRandomString(6))
	userToken := model.UserToken{}
	userToken.ProjectID = user.ProjectID
	userToken.Uid = user.Id
	userToken.Token = token
	userToken.Ip = ip
	userToken.LoginType = 1
	userToken.CreateTime = &now
	err = model.DB.Create(&userToken).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	projectExist := &model.Project{}
	exist, err := projectExist.Exists(param.ProjectID)
	if !exist {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "工程不存在",
			"data":    err,
		})
		return
	}
	isSuper := false
	role := &model.AuthRole{}
	if projectExist.UID == user.Id {
		isSuper = true
	} else {
		_, _ = role.Exists(user.Role)
	}
	jsonByte, _ := json.Marshal(userToken)
	_ = j_redis.RedisDb.Set(context.Background(), token, string(jsonByte), time.Hour*24*7).Err()

	ip, port := tools.GetIPPortFromHost(ctx.Request.Host)
	updateData := make(map[string]interface{})
	updateData["server_ip"] = ip
	updateData["server_port"] = port
	_ = model.DB.Model(&model.Project{}).Where("id = ?", param.ProjectID).Updates(updateData).Error

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"uid":        user.Id,
			"project_id": user.ProjectID,
			"username":   user.Username,
			"realname":   user.Realname,
			"avatar":     user.Avatar,
			"token":      token,
			"is_super":   isSuper,
			"role_info":  role,
		},
	})

}

func (con LoginController) Logout(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	oldToken := userToken.Token
	err := model.DB.Model(&model.UserToken{}).Where("token = ?", oldToken).Update("token", "").Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	err = j_redis.RedisDb.Del(context.Background(), oldToken).Err()
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    8,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
	})

}

func (con LoginController) LoginInfo(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	old := &model.User{}
	exist, err := old.Exists(userToken.Uid)
	if !exist {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "Uid未找到",
			"data":    err,
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"token_data": userToken,
			"user_data":  old,
		},
	})

}

func (con LoginController) CheckToken(ctx *gin.Context) {
	param := struct {
		Token string `json:"token"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	token := param.Token
	if token == "" {
		ctx.JSON(200, gin.H{
			"code":    3,
			"message": "请传入token",
		})
		return
	}
	res, _ := j_redis.RedisDb.Get(context.Background(), token).Result()
	if res == "" {
		ctx.JSON(200, gin.H{
			"code":    4,
			"message": "token无效",
		})
		return
	}
	tokenInfo := model.UserToken{}
	err = json.Unmarshal([]byte(res), &tokenInfo)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": err.Error(),
		})
		return
	}

	if time.Now().Unix()-tools.StrToTimeStamp(*tokenInfo.CreateTime) > 3600*24*2 {
		ctx.JSON(200, gin.H{
			"code":    4,
			"message": "token失效",
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    tokenInfo,
	})
}

func (con LoginController) RefreshToken(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	oldToken := userToken.Token
	newToken := tools.Md5(strconv.Itoa(userToken.Uid) + strconv.FormatInt(time.Now().UnixNano(), 10) + tools.GetRandomString(6))
	// 判断数据库中token 存在与否及状态
	tokenInfo := model.UserToken{}
	err := model.DB.Where("token = ?", oldToken).First(&tokenInfo).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    61,
			"message": err.Error(),
		})
		return
	}
	// mysql 更新 token
	tokenInfo.Token = newToken
	tokenInfo.RefreshTimes = tokenInfo.RefreshTimes + 1
	err = model.DB.Model(&model.UserToken{}).Where("id = ?", tokenInfo.Id).Updates(tokenInfo).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    62,
			"message": err.Error(),
		})
		return
	}
	now := tools.GetNow()
	// redis 存入新token 删除旧token( 旧token过期时间设为60秒后 )
	userToken.Token = newToken
	userToken.CreateTime = &now
	jsonByte, _ := json.Marshal(userToken)
	_ = j_redis.RedisDb.Set(context.Background(), newToken, string(jsonByte), 48*time.Hour).Err()
	_ = j_redis.RedisDb.Expire(context.Background(), oldToken, time.Second*60).Err()

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    newToken,
	})
}
